#!/usr/bin/env python

import cStringIO
from wsgiref.handlers import BaseCGIHandler
from runner.runner import Runner
import re
import os

_requires = ['renyare.application']

class IncluderCGIHandler(BaseCGIHandler):
	"""
	Child class to override unneeded output
	"""
	os_environ = {}
	def send_headers(self):
		# In our case we don't need to write headers and preamble to stdout
		self.headers_sent = True

	def close(self):
		"""Close the iterable (if needed) and reset all instance vars
		Subclasses may want to also drop the client connection.
		"""
		try:
			if hasattr(self.result,'close'):
				self.result.close()
		finally:
			self.base_env.update(self.environ) # Return all changes back to up-level environ
			self.result = self.headers = self.status = self.environ = None
			self.bytes_sent = 0; self.headers_sent = False

class Includer:
	"""
	A side-end framework, that runs the application without changes, but runs a number of other provided applications
	and places their it's output in other location.
	This is useful if you want to include such output in certain the area of the site
	Keywords:
		- config - list of tuples, that should be in such form:
			('application', {'type':'<app-type>', 'module':'<app-module-to-import>'})
	"""
	def __init__(self, app, **kw):
		self.orig_app = app
		self.config = kw.get('config') or []
		self.apps = []
		for cnf in self.config:
			env = {}
			if(cnf[0] == 'application' and cnf[1].has_key('type') and cnf[1].has_key('module')):
				app  = Runner(cnf[1]['module'], cnf[1]['type'])
				self.apps.append( app )

	def __call__(self, environ, start_response):
		self.environ = environ
		self.start_response = start_response
		self.init_apps = []
		for app in self.apps:
			self.curr_app = [None, None]
			self.curr_app[0] = app(environ, self.fake_start_response).__iter__()
			self.curr_app[1] = environ['renyare.application']
			self.init_apps.append(self.curr_app)

		app_iter = self.iter_apps()
		for data in self.orig_app(environ, start_response):
			yield data
			n = ''
			try:
				n = app_iter.next()
			except StopIteration:
				pass
			yield ''
		# If some data in applications is left
		stop = False
		while(not stop):
			try:
				n = app_iter.next()
			except StopIteration:
				stop = True
			yield n


	def iter_apps(self):
		while(self.init_apps):
			remove = []
			for app in self.init_apps:
				self.environ['renyare.application'] = app[1]
				n = ''
				try:
					n = app[0].next()
				except StopIteration:
					remove.append(app)
				yield n
			[self.init_apps.remove(x) for x in remove]

	def fake_start_response(self, status, headers, exc_info=None):
		self.curr_app[1]['status'] = status
		self.curr_app[1]['headers'] = headers
		return self.fake_write # start_response have to return write function

	def fake_write(self, string):
		pass

	def smart_update(self, src, dst, key, val):
		if(not dst.has_key(key)):
			dst[key] = val
		elif(type(val) is type(dst[key])):
			if(isinstance(val, dict)):
				dst[key].update(val)
			else:
				dst[key] = val
		else:
			raise renyare.error.Error("Cannot join environment variables for key %s: Types mismatch." % key)
